home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Tools / Freeware / CheckDisk / Src / CheckDisk.c next >
Encoding:
C/C++ Source or Header  |  2002-10-28  |  31.3 KB  |  935 lines

  1. /*
  2. **    $RCSfile: CheckDisk.c,v $
  3. **    $Filename: CheckDisk.c $
  4. **    $Revision: 0.1 $
  5. **    $Date: 1997/04/12 17:33:51 $
  6. **
  7. **    Check a disk device for hard errors (version 0.7)
  8. **
  9. **    (C) Copyright 1997-2002 by Etienne Vogt
  10. */
  11.  
  12. #include <exec/alerts.h>
  13. #include <exec/memory.h>
  14. #include <exec/io.h>
  15. #include <dos/dos.h>
  16. #include <dos/dosextens.h>
  17. #include <dos/dosasl.h>
  18. #include <dos/dostags.h>
  19. #include <dos/filehandler.h>
  20. #include <workbench/startup.h>
  21. #include <devices/newstyle.h>
  22. #include <devices/trackdisk.h>
  23. #include <libraries/multiuser.h>
  24. #define __USE_SYSBASE
  25. #include <proto/exec.h>
  26. #include <proto/dos.h>
  27. #include <proto/multiuser.h>
  28. #include <clib/alib_protos.h>
  29. #include <string.h>
  30. #include "ffs.h"
  31.  
  32. struct DiskDevice mydiskdev;
  33.  
  34. #define    BBL_SIZE    64        /* Number of bad blocks in one table */
  35.  
  36. struct BadBlockList
  37. {    struct BadBlockList *bbl_Link;        /* Pointer to next structure */
  38.     ULONG    bbl_BadBlocks[BBL_SIZE];    /* Key IDs of bad blocks */
  39. };
  40.  
  41. #define ID_MUFS_DISK    0x6d754653        /* DosType for multiuser filesystem */
  42.  
  43. #define FIBB_HOLD    7            /* h protection bit (hold/hidden) */
  44. #define FIBF_HOLD    (1L << FIBB_HOLD)
  45.  
  46. #define    DDFB_READWRITE    31        /* non-destructive write test */
  47. #define    DDFB_MODIFIED    30        /* Bad block mappings have changed */
  48.  
  49. #define DDFF_READWRITE    (1L << DDFB_READWRITE)
  50. #define    DDFF_MODIFIED    (1L << DDFB_MODIFIED)
  51.  
  52. #define NUMBBNAMES    3
  53.  
  54. static STRPTR BadBlockFileNames[] = { "BadBlocks.sys", "[secteurs.hs]", "bad.blocks" };
  55.  
  56. struct ExecBase *SysBase;
  57. struct DosLibrary *DOSBase;
  58. struct muBase *muBase;
  59. struct MsgPort *DeviceMP;
  60. struct IOStdReq *DeviceIO;
  61. static struct WBStartup *wbmsg;
  62. static struct RDArgs *myrda;
  63. static struct BadBlockList *BBList;
  64. static ULONG *bitmap, *rootblock;
  65.  
  66. static UBYTE version[] = "$VER: CheckDisk 0.7 (4.8.2002)";
  67. static UBYTE template[] = "DEVICE/A,NOINHIBIT/S,RW=READWRITE/S,S=SEVERE/S,RESET/S,LO=LOWCYL/K/N,HI=HIGHCYL/K/N,V=VERBOSE/S,BUFCYL/K/N";
  68.  
  69. #define    OPT_DEVICE    0
  70. #define OPT_NOINHIBIT    1
  71. #define OPT_READWRITE    2
  72. #define    OPT_SEVERE    3
  73. #define OPT_RESET    4
  74. #define OPT_LOWCYL    5
  75. #define OPT_HIGHCYL    6
  76. #define OPT_VERBOSE    7
  77. #define    OPT_BUFCYL    8
  78. #define OPTMAX        9
  79.  
  80. ULONG __saveds main(void);
  81. static void cleanexit(ULONG rc);
  82. static int checkdisk(void);
  83. static int checkcyl(struct IOStdReq *ioreq, APTR buffer, ULONG bufsize, int cyl);
  84. static int checkbysectors(struct IOStdReq *ioreq, APTR buffer, ULONG size, int cyl, int starthead);
  85. static BPTR openbadblocksfile(STRPTR device);
  86. static struct BadBlockList *readbadblocks(BPTR bbflock);
  87. static int writebadblocks(struct BadBlockList *bbl, BPTR bbflock);
  88. static void freebadblocklist(struct BadBlockList *bbl);
  89. static BOOL checkbadblock(ULONG KeyID);
  90. static void mapbadblock(ULONG badcyl, ULONG badhead, ULONG badsector);
  91. static BOOL addbadblock(ULONG KeyID);
  92. static ULONG getfreeblock(ULONG *bitmap);
  93. static void freebadblocks(struct BadBlockList *bbl);
  94. static __inline BOOL checkprotection(struct IOStdReq *ioreq);
  95. static __inline BOOL checkstate(struct IOStdReq *ioreq);
  96.  
  97. ULONG __saveds main(void)    /* No startup code */
  98. { struct Process *myproc;
  99.   LONG opts[OPTMAX];
  100.   ULONG rc = 0;
  101.  
  102.   SysBase = *(struct ExecBase **)4;
  103.   DOSBase = NULL;
  104.   wbmsg = NULL;
  105.   myrda = NULL;
  106.  
  107.   myproc = (struct Process *)FindTask(NULL);
  108.   if ((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",36)) == NULL)
  109.   { Alert(AT_Recovery|AG_OpenLib|AO_DOSLib);
  110.     return 100;
  111.   }
  112.  
  113.   if (!(myproc->pr_CLI))        /* If started from WB, exit cleanly */
  114.   { WaitPort(&(myproc->pr_MsgPort));
  115.     wbmsg = (struct WBStartup *)GetMsg(&(myproc->pr_MsgPort));
  116.     cleanexit(20);
  117.   }
  118.   else
  119.   { APTR oldwinptr;
  120.     int error = 0;
  121.     struct DosList *dol;
  122.     struct FileSysStartupMsg *startup;
  123.     struct DosEnvec *dosenv;
  124.     STRPTR fssmdev;
  125.     char buffer[DNAME_SIZE];
  126.     UBYTE *colon;
  127.     BYTE TDretries = 0;
  128.  
  129.     memset((char *)opts, 0, sizeof(opts));
  130.     if ((myrda = ReadArgs(template, opts, NULL)) == NULL)
  131.     { PrintFault(IoErr(),"CheckDisk");
  132.       cleanexit(20);
  133.     }
  134.  
  135.     oldwinptr = myproc->pr_WindowPtr;        /* Disable DOS Requesters    */
  136.     myproc->pr_WindowPtr = (APTR)(-1L);
  137.  
  138.     dol = LockDosList(LDF_DEVICES | LDF_READ);
  139.     strncpy(buffer, (STRPTR)opts[OPT_DEVICE], sizeof(buffer));
  140.     if (colon = (UBYTE *)strchr(buffer,':')) *colon = (UBYTE)0;
  141.     else buffer[DNAME_SIZE-1] = (UBYTE)0;
  142.     if (dol = FindDosEntry(dol, buffer, LDF_DEVICES))
  143.     { startup = BADDR(((struct DeviceNode *)dol)->dn_Startup);
  144.       if (TypeOfMem(startup) && ((ULONG)startup & 1) == 0)
  145.       { fssmdev = (STRPTR)BADDR(startup->fssm_Device) + 1;
  146.     if (TypeOfMem(fssmdev))
  147.     { strncpy(mydiskdev.dd_DeviceName, fssmdev, DNAME_SIZE - 1);
  148.       mydiskdev.dd_DeviceUnit = startup->fssm_Unit;
  149.       mydiskdev.dd_DeviceFlags = startup->fssm_Flags;
  150.       dosenv = BADDR(startup->fssm_Environ);
  151.       if (TypeOfMem(dosenv) && ((ULONG)dosenv & 1) == 0 && dosenv->de_TableSize >= 11)
  152.       { mydiskdev.dd_SectorSize = dosenv->de_SizeBlock << 2;
  153.         mydiskdev.dd_SectorsPerBlock = dosenv->de_SectorPerBlock;
  154.         mydiskdev.dd_SectorsPerTrack = dosenv->de_BlocksPerTrack;
  155.         mydiskdev.dd_Surfaces = dosenv->de_Surfaces;
  156.         mydiskdev.dd_LowCyl = dosenv->de_LowCyl;
  157.         mydiskdev.dd_HighCyl = dosenv->de_HighCyl;
  158.         mydiskdev.dd_Reserved = dosenv->de_Reserved;
  159.         if (dosenv->de_TableSize >= 12) mydiskdev.dd_BufMemType = dosenv->de_BufMemType;
  160.         else mydiskdev.dd_BufMemType = MEMF_ANY;
  161.         if (dosenv->de_TableSize >= 13) mydiskdev.dd_MaxTransfer = dosenv->de_MaxTransfer;
  162.         else mydiskdev.dd_MaxTransfer = 0x1fe00;
  163.         if (dosenv->de_TableSize >= 16) mydiskdev.dd_DOSType = dosenv->de_DosType;
  164.         else mydiskdev.dd_DOSType = ID_DOS_DISK;
  165.       }
  166.       else error = -1;
  167.     }
  168.     else error = -2;
  169.       }
  170.       else error = -3;
  171.       UnLockDosList(LDF_DEVICES | LDF_READ);
  172.       myproc->pr_WindowPtr = oldwinptr;
  173.       strcat(buffer, ":");
  174.  
  175.       if (error)
  176.       { Printf("CheckDisk: %s is not a disk structured device (%ld)\n",opts[OPT_DEVICE],error);
  177.     cleanexit(20);
  178.       }
  179.  
  180.       if (opts[OPT_LOWCYL])
  181.       { mydiskdev.dd_LowCyl = *(ULONG *)opts[OPT_LOWCYL];
  182.     mydiskdev.dd_Flags |= DDFF_CUSTOM;
  183.       }
  184.       if (opts[OPT_HIGHCYL])
  185.       { mydiskdev.dd_HighCyl = *(ULONG *)opts[OPT_HIGHCYL];
  186.     mydiskdev.dd_Flags |= DDFF_CUSTOM;
  187.       }
  188.       if (opts[OPT_READWRITE]) mydiskdev.dd_Flags |= DDFF_READWRITE;
  189.       if (opts[OPT_VERBOSE]) mydiskdev.dd_Flags |= DDFF_VERBOSE;
  190.       if (opts[OPT_BUFCYL]) mydiskdev.dd_CylStep = *(ULONG *)opts[OPT_BUFCYL];
  191.       else mydiskdev.dd_CylStep = 1;
  192.  
  193.       if (mydiskdev.dd_Flags & DDFF_VERBOSE)
  194.       { Printf("Device        = %.32s\n", mydiskdev.dd_DeviceName);
  195.     Printf("Unit        = %ld\n", mydiskdev.dd_DeviceUnit);
  196.     Printf("Flags        = %08lx\n", mydiskdev.dd_DeviceFlags);
  197.     Printf("SectorSize    = %lu\n", mydiskdev.dd_SectorSize);
  198.     Printf("SectorsPerBlock = %lu\n", mydiskdev.dd_SectorsPerBlock);
  199.     Printf("SectorsPerTrack = %lu\n", mydiskdev.dd_SectorsPerTrack);
  200.     Printf("Surfaces    = %lu\n", mydiskdev.dd_Surfaces);
  201.     Printf("LowCyl        = %lu\n", mydiskdev.dd_LowCyl);
  202.     Printf("HighCyl        = %lu\n", mydiskdev.dd_HighCyl);
  203.     Printf("Reserved    = %lu\n", mydiskdev.dd_Reserved);
  204.     Printf("BufMemType    = %lu\n", mydiskdev.dd_BufMemType);
  205.     Printf("MaxTransfer    = %08lx\n", mydiskdev.dd_MaxTransfer);
  206.     Printf("DosType         = %08lx\n", mydiskdev.dd_DOSType);
  207.       }
  208.  
  209.       if (DeviceMP = CreateMsgPort())
  210.       { if (DeviceIO = CreateIORequest(DeviceMP, sizeof(struct IOStdReq)))
  211.     { if ((error = OpenDevice(mydiskdev.dd_DeviceName, mydiskdev.dd_DeviceUnit, (struct IORequest *)DeviceIO, mydiskdev.dd_DeviceFlags)) == 0)
  212.       { BPTR bb_lock=0;
  213.         ULONG *bootblock;
  214.         char inbuf[4];
  215.  
  216.     /* Check if a disk in present and if it is write enabled */
  217.  
  218.         while (checkstate(DeviceIO))
  219.         { PutStr("There's no disk in the drive !\n");
  220.           PutStr("Insert a disk and hit return to continue\n");
  221.           FGets(Input(), inbuf, sizeof(inbuf) - 1);
  222.           Flush(Input());
  223.           PutStr("\n");
  224.         }
  225.  
  226.         if (checkprotection(DeviceIO))
  227.         { PutStr("Disk is write protected !\n");
  228.           PutStr("Bad block mapping is disabled\n\n");
  229.           mydiskdev.dd_Flags |= DDFF_CUSTOM;
  230.         }
  231.  
  232.     /* Check if we need 64bit commands and if they are available */
  233.  
  234.         if (error = initFFS())
  235.         { PrintFault(error, "CheckDisk");
  236.           cleanexit(20);
  237.         }
  238.  
  239.     /* Try to read the boot block, and update the volume DOS ID */
  240.  
  241.         if (!(mydiskdev.dd_Flags & DDFF_CUSTOM))
  242.         { if (bootblock = readblock(0))
  243.           { mydiskdev.dd_DOSType = bootblock[BOOT_ID];
  244.         FreeVec(bootblock);
  245.           }
  246.           else
  247.           { Printf("Warning: Couldn't read volume boot block (error %ld)\n", DeviceIO->io_Error);
  248.         mydiskdev.dd_Flags |= DDFF_CUSTOM;
  249.           }
  250.         }
  251.  
  252.         if ((mydiskdev.dd_DOSType & ID_DOS_DISK) != ID_DOS_DISK && mydiskdev.dd_DOSType != ID_MUFS_DISK)
  253.           mydiskdev.dd_Flags |= DDFF_CUSTOM;
  254.  
  255.     /* If we are scanning an AmigaDOS volume, check for an existing badblocks file */
  256.  
  257.         if (!(mydiskdev.dd_Flags & DDFF_CUSTOM) && (bb_lock = openbadblocksfile(buffer)))
  258.         { if (!(BBList = readbadblocks(bb_lock))) PutStr("Warning: Couldn't read existing bad blocks file\n");
  259.         }
  260.  
  261.         if (!opts[OPT_NOINHIBIT])
  262.         { if (Inhibit(buffer, DOSTRUE) == DOSFALSE)
  263.           { Printf("CheckDisk: couldn't inhibit drive %s\n", buffer);
  264.         freebadblocklist(BBList);
  265.         if (bb_lock) UnLock(bb_lock);
  266.         cleanexit(20);
  267.           }
  268.         }
  269.  
  270.     /* If we are scanning an AmigaDOS volume, read root block and bitmap */
  271.  
  272.         if (!(mydiskdev.dd_Flags & DDFF_CUSTOM))
  273.         { if (rootblock = readblock(mydiskdev.dd_RootKey))
  274.           { if (error = checkblock(rootblock, mydiskdev.dd_RootKey, T_SHORT, ST_ROOT))
  275.         { Printf("Warning: Invalid root block (error %ld)\n", error);
  276.           FreeVec(rootblock);
  277.           rootblock = NULL;
  278.           mydiskdev.dd_Flags |= DDFF_CUSTOM;
  279.         }
  280.         else
  281.         { if (rootblock[mydiskdev.dd_BlockSizeL+ROOT_BITMAPFLAG])
  282.           { if (mydiskdev.dd_Flags & DDFF_VERBOSE) PutStr("\nReading volume bitmap\n");
  283.             if (!(bitmap = readbitmap(rootblock)))
  284.             { PutStr("Warning: Couldn't read volume bitmap\n");
  285.               FreeVec(rootblock);
  286.               rootblock = NULL;
  287.               mydiskdev.dd_Flags |= DDFF_CUSTOM;
  288.             }
  289.             else if (opts[OPT_RESET])
  290.             { freebadblocks(BBList);        /* Ignore existing bad blocks, mark them free */
  291.               freebadblocklist(BBList);
  292.               BBList = NULL;
  293.               mydiskdev.dd_Flags |= DDFF_MODIFIED;
  294.             }
  295.           }
  296.           else
  297.           { PutStr("Warning: Volume bitmap is invalid\n");
  298.             FreeVec(rootblock);
  299.             rootblock = NULL;
  300.             mydiskdev.dd_Flags |= DDFF_CUSTOM;
  301.           }
  302.         }
  303.           }
  304.           else
  305.           { Printf("Warning: Couldn't read volume root block (error %ld)\n", DeviceIO->io_Error);
  306.         mydiskdev.dd_Flags |= DDFF_CUSTOM;
  307.           }
  308.         }
  309.  
  310.           /* If severe mode requested, disable retries for trackdisk unit */
  311.  
  312.         if (opts[OPT_SEVERE] && !strcmp(mydiskdev.dd_DeviceName, TD_NAME) && DeviceIO->io_Unit)
  313.         { TDretries = ((struct TDU_PublicUnit *)DeviceIO->io_Unit)->tdu_RetryCnt;
  314.           ((struct TDU_PublicUnit *)DeviceIO->io_Unit)->tdu_RetryCnt = 0;
  315.         }
  316.  
  317.         if (error = checkdisk())
  318.         { PrintFault(error, "CheckDisk");
  319.           rc = 10;
  320.         }
  321.  
  322.         if (opts[OPT_SEVERE] && TDretries) ((struct TDU_PublicUnit *)DeviceIO->io_Unit)->tdu_RetryCnt = TDretries;
  323.  
  324.     /* If the bad block list was modified, write the bad blocks file back */
  325.  
  326.         if (!rc && mydiskdev.dd_Flags & DDFF_MODIFIED)
  327.         { writebadblocks(BBList, bb_lock);
  328.           DateStamp((struct DateStamp *)&rootblock[mydiskdev.dd_BlockSizeL+ROOT_VOLUMEDAYS]);
  329.           rootblock[mydiskdev.dd_BlockSizeL+ROOT_BITMAPFLAG] = 0; /* Mark bitmap as dirty */
  330.           sumblock(rootblock);
  331.           if (error = writeblock(rootblock, mydiskdev.dd_RootKey))
  332.         Printf("Error: Couldn't write back volume root block (error %ld)\n", error);
  333.         }
  334.  
  335.         if (BBList) freebadblocklist(BBList);
  336.         if (bitmap) FreeVec(bitmap);
  337.         if (rootblock) FreeVec(rootblock);
  338.  
  339.         if (!opts[OPT_NOINHIBIT]) Inhibit(buffer, DOSFALSE);
  340.  
  341.         if (bb_lock) UnLock(bb_lock);
  342.         CloseDevice((struct IORequest *)DeviceIO);
  343.         DeviceIO->io_Device = NULL;
  344.       }
  345.       else Printf("Unable to open %s unit %ld\n", mydiskdev.dd_DeviceName, mydiskdev.dd_DeviceUnit);
  346.       DeleteIORequest(DeviceIO);
  347.       DeviceIO = NULL;
  348.     }
  349.     else
  350.     { PutStr("Unable to create IORequest\n");
  351.       PrintFault(ERROR_NO_FREE_STORE, "CheckDisk");
  352.     }
  353.     DeleteMsgPort(DeviceMP);
  354.     DeviceMP = NULL;
  355.       }
  356.       else
  357.       { PutStr("Unable to create MsgPort\n");
  358.     PrintFault(ERROR_NO_FREE_STORE, "CheckDisk");
  359.       }
  360.  
  361.     }
  362.     else
  363.     { UnLockDosList(LDF_DEVICES | LDF_READ);
  364.       PrintFault(ERROR_DEVICE_NOT_MOUNTED, "CheckDisk");
  365.       rc = 20;
  366.     }
  367.  
  368.   }
  369.   cleanexit(rc);
  370. }
  371.  
  372. static void cleanexit(ULONG rc)
  373. {
  374.   if (DeviceIO && DeviceIO->io_Device) CloseDevice((struct IORequest *)DeviceIO);
  375.   if (DeviceIO) DeleteIORequest(DeviceIO);
  376.   if (DeviceMP) DeleteMsgPort(DeviceMP);
  377.   if (myrda) FreeArgs(myrda);
  378.   if (DOSBase) CloseLibrary((struct Library *)DOSBase);
  379.   if (wbmsg)
  380.   { Forbid();
  381.     ReplyMsg((struct Message *)wbmsg);
  382.   }
  383.   Exit(rc);
  384. }
  385.  
  386. static int checkdisk(void)
  387. { int error=0, cyl;
  388.   ULONG bufsize = mydiskdev.dd_SectorSize * mydiskdev.dd_SectorsPerCyl;
  389.   APTR buffer = NULL;
  390.  
  391.   if (mydiskdev.dd_CylStep > 1)
  392.   { bufsize *= mydiskdev.dd_CylStep;
  393.     if (bufsize > mydiskdev.dd_MaxTransfer || (buffer = AllocMem(bufsize, mydiskdev.dd_BufMemType)) == NULL)
  394.     { bufsize /= mydiskdev.dd_CylStep;
  395.       mydiskdev.dd_CylStep = 1;
  396.     }
  397.   }
  398.   if (!buffer)
  399.   { if (bufsize > mydiskdev.dd_MaxTransfer || (buffer = AllocMem(bufsize, mydiskdev.dd_BufMemType)) == NULL)
  400.     { bufsize = mydiskdev.dd_SectorSize * mydiskdev.dd_SectorsPerTrack; /* Else try full tracks */
  401.       if (bufsize > mydiskdev.dd_MaxTransfer || (buffer = AllocMem(bufsize, mydiskdev.dd_BufMemType)) == NULL)
  402.       { bufsize = mydiskdev.dd_SectorSize; /* Finally try single sectors */
  403.     buffer = AllocMem(bufsize, mydiskdev.dd_BufMemType);
  404.       }
  405.     }
  406.   }
  407.  
  408.   if (buffer)
  409.   { if (mydiskdev.dd_Flags & DDFF_VERBOSE)
  410.     { Printf("\nBuffer          = %08lx\n", buffer);
  411.       Printf("BufSize          = %lu\n", bufsize);
  412.       PutStr("\n");
  413.     }
  414.  
  415.     for (cyl = mydiskdev.dd_LowCyl ; cyl <= mydiskdev.dd_HighCyl ; cyl += mydiskdev.dd_CylStep)
  416.     { checkcyl(DeviceIO, buffer, bufsize, cyl);
  417.       if (CheckSignal(SIGBREAKF_CTRL_C))
  418.       { PutStr("\nAborted !\n");
  419.     error = ERROR_BREAK;
  420.     break;
  421.       }
  422.     }
  423.     PutStr("\n");
  424.  
  425.     FreeMem(buffer, bufsize);
  426.   }
  427.   else
  428.   { Printf("Unable to allocate %lu bytes for data buffer\n", bufsize);
  429.     error = ERROR_NO_FREE_STORE;
  430.   }
  431.  
  432.   return error;
  433. }
  434.  
  435. #define    io_HighOffset    io_Actual
  436.  
  437. static int checkcyl(struct IOStdReq *ioreq, APTR buffer, ULONG bufsize, int cyl)
  438. { ULONG cylsize, tracksize, cylsize512, tracksize512;
  439.   int error, head, cyl1;
  440.  
  441.   tracksize = mydiskdev.dd_SectorSize * mydiskdev.dd_SectorsPerTrack;
  442.   cylsize = tracksize * mydiskdev.dd_Surfaces;
  443.   cylsize512 = cylsize / 512;
  444.   tracksize512 = tracksize / 512;
  445.   Printf("Checking cylinder %ld\r", cyl);
  446.   Flush(Output());
  447.  
  448.   if (bufsize == cylsize * mydiskdev.dd_CylStep)
  449.   { ioreq->io_Data = buffer;
  450.     ioreq->io_Length = cyl+mydiskdev.dd_CylStep > mydiskdev.dd_HighCyl+1 ? (mydiskdev.dd_HighCyl-cyl+1)*cylsize : bufsize;
  451.     ioreq->io_Offset = cyl * cylsize;
  452.     if (mydiskdev.dd_Flags & DDFF_DO64BIT)
  453.     { ioreq->io_Command = NSCMD_TD_READ64;
  454.       ioreq->io_HighOffset = cyl * cylsize512 / (8*1024*1024);
  455.     }
  456.     else ioreq->io_Command = CMD_READ;
  457.     if (error = DoIO((struct IORequest *)ioreq))
  458.     { for (cyl1 = cyl ; cyl1 < cyl + mydiskdev.dd_CylStep ; cyl1++)
  459.       { checkbysectors(ioreq, buffer, cylsize, cyl1, 0);
  460.     if (cyl1 == mydiskdev.dd_HighCyl || SetSignal(0,0) & SIGBREAKF_CTRL_C) break;
  461.       }
  462.     }
  463.     if (mydiskdev.dd_Flags & DDFF_READWRITE && error == 0)
  464.     { ioreq->io_Data = buffer;
  465.       ioreq->io_Length = cyl+mydiskdev.dd_CylStep > mydiskdev.dd_HighCyl+1 ? (mydiskdev.dd_HighCyl-cyl+1)*cylsize : bufsize;
  466.       ioreq->io_Offset = cyl * cylsize;
  467.       if (mydiskdev.dd_Flags & DDFF_DO64BIT)
  468.       { ioreq->io_Command = NSCMD_TD_WRITE64;
  469.     ioreq->io_HighOffset = cyl * cylsize512 / (8*1024*1024);
  470.       }
  471.       else ioreq->io_Command = CMD_WRITE;
  472.       if (error = DoIO((struct IORequest *)ioreq))
  473.       { for (cyl1 = cyl ; cyl1 < cyl + mydiskdev.dd_CylStep ; cyl1++)
  474.     { checkbysectors(ioreq, buffer, cylsize, cyl, 0);
  475.       if (cyl1 == mydiskdev.dd_HighCyl || SetSignal(0,0) & SIGBREAKF_CTRL_C) break;
  476.     }
  477.       }
  478.     }
  479.   }
  480.   else if (bufsize == cylsize)
  481.   { ioreq->io_Data = buffer;
  482.     ioreq->io_Length = bufsize;
  483.     ioreq->io_Offset = cyl * cylsize;
  484.     if (mydiskdev.dd_Flags & DDFF_DO64BIT)
  485.     { ioreq->io_Command = NSCMD_TD_READ64;
  486.       ioreq->io_HighOffset = cyl * cylsize512 / (8*1024*1024);
  487.     }
  488.     else ioreq->io_Command = CMD_READ;
  489.     if (error = DoIO((struct IORequest *)ioreq)) checkbysectors(ioreq, buffer, cylsize, cyl, 0);
  490.     if (mydiskdev.dd_Flags & DDFF_READWRITE && error == 0)
  491.     { ioreq->io_Data = buffer;
  492.       ioreq->io_Length = bufsize;
  493.       ioreq->io_Offset = cyl * cylsize;
  494.       if (mydiskdev.dd_Flags & DDFF_DO64BIT)
  495.       { ioreq->io_Command = NSCMD_TD_WRITE64;
  496.     ioreq->io_HighOffset = cyl * cylsize512 / (8*1024*1024);
  497.       }
  498.       else ioreq->io_Command = CMD_WRITE;
  499.       if (error = DoIO((struct IORequest *)ioreq)) checkbysectors(ioreq, buffer, cylsize, cyl, 0);
  500.     }
  501.   }
  502.   else if (bufsize == tracksize)
  503.   { for (head = 0 ; head < mydiskdev.dd_Surfaces ; head++)
  504.     { ioreq->io_Data = buffer;
  505.       ioreq->io_Length = bufsize;
  506.       ioreq->io_Offset = cyl * cylsize + head * tracksize;
  507.       if (mydiskdev.dd_Flags & DDFF_DO64BIT)
  508.       { ioreq->io_Command = NSCMD_TD_READ64;
  509.     ioreq->io_HighOffset = (cyl * cylsize512 + head * tracksize512) / (8*1024*1024);
  510.       }
  511.       else ioreq->io_Command = CMD_READ;
  512.       if (error = DoIO((struct IORequest *)ioreq)) checkbysectors(ioreq, buffer, tracksize, cyl, head);
  513.       if (mydiskdev.dd_Flags & DDFF_READWRITE && error == 0)
  514.       { ioreq->io_Data = buffer;
  515.     ioreq->io_Length = bufsize;
  516.     ioreq->io_Offset = cyl * cylsize + head * tracksize;
  517.     if (mydiskdev.dd_Flags & DDFF_DO64BIT)
  518.     { ioreq->io_Command = NSCMD_TD_WRITE64;
  519.       ioreq->io_HighOffset = (cyl * cylsize512 + head * tracksize512) / (8*1024*1024);
  520.     }
  521.     else ioreq->io_Command = CMD_WRITE;
  522.     if (error = DoIO((struct IORequest *)ioreq)) checkbysectors(ioreq, buffer, tracksize, cyl, head);
  523.       }
  524.     }
  525.   }
  526.   else error = checkbysectors(ioreq, buffer, cylsize, cyl, 0);
  527.  
  528.   return error;
  529. }
  530.  
  531. static int checkbysectors(struct IOStdReq *ioreq, APTR buffer, ULONG size, int cyl, int starthead)
  532. { ULONG cylsize, tracksize, cylsize512, tracksize512, sectorsize512;
  533.   int error, head, sector, endhead;
  534.  
  535.   tracksize = mydiskdev.dd_SectorSize * mydiskdev.dd_SectorsPerTrack;
  536.   cylsize = tracksize * mydiskdev.dd_Surfaces;
  537.   cylsize512 = cylsize / 512;
  538.   tracksize512 = tracksize / 512;
  539.   sectorsize512 = mydiskdev.dd_SectorSize / 512;
  540.   if (size == tracksize) endhead = starthead + 1;
  541.   else endhead = mydiskdev.dd_Surfaces;
  542.  
  543.   if (mydiskdev.dd_Flags & DDFF_VERBOSE) PutStr("\n");
  544.   for (head = starthead ; head < endhead ; head++)
  545.   { for (sector = 0 ; sector < mydiskdev.dd_SectorsPerTrack ; sector++)
  546.     { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("Checking cylinder %ld, head %ld, sector %ld    \r", cyl, head, sector);
  547.       ioreq->io_Data = buffer;
  548.       ioreq->io_Length = mydiskdev.dd_SectorSize;
  549.       ioreq->io_Offset = cyl * cylsize + head * tracksize + sector * mydiskdev.dd_SectorSize;
  550.       if (mydiskdev.dd_Flags & DDFF_DO64BIT)
  551.       { ioreq->io_Command = NSCMD_TD_READ64;
  552.     ioreq->io_HighOffset = (cyl * cylsize512 + head * tracksize512 + sector * sectorsize512) / (8*1024*1024);
  553.       }
  554.       else ioreq->io_Command = CMD_READ;
  555.       if (error = DoIO((struct IORequest *)ioreq))
  556.       { Printf("Read error %ld on cylinder %ld head %ld sector %ld\n", error, cyl, head, sector);
  557.     if (!(mydiskdev.dd_Flags & DDFF_CUSTOM)) mapbadblock(cyl, head, sector);
  558.       }
  559.       if (mydiskdev.dd_Flags & DDFF_READWRITE && error == 0)
  560.       { ioreq->io_Data = buffer;
  561.     ioreq->io_Length = mydiskdev.dd_SectorSize;
  562.     ioreq->io_Offset = cyl * cylsize + head * tracksize + sector * mydiskdev.dd_SectorSize;
  563.     if (mydiskdev.dd_Flags & DDFF_DO64BIT)
  564.     { ioreq->io_Command = NSCMD_TD_WRITE64;
  565.       ioreq->io_HighOffset = (cyl * cylsize512 + head * tracksize512 + sector * sectorsize512) / (8*1024*1024);
  566.     }
  567.     else ioreq->io_Command = CMD_WRITE;
  568.     if (error = DoIO((struct IORequest *)ioreq))
  569.     { Printf("Write error %ld on cylinder %ld head %ld sector %ld\n", error, cyl, head, sector);
  570.       if (!(mydiskdev.dd_Flags & DDFF_CUSTOM)) mapbadblock(cyl, head, sector);
  571.     }
  572.       }
  573.     }
  574.   }
  575.  
  576.   if (mydiskdev.dd_Flags & DDFF_VERBOSE) PutStr("\n");
  577.   return error;
  578. }
  579.  
  580. static BPTR openbadblocksfile(STRPTR device)
  581. { char buffer[DNAME_SIZE];
  582.   BPTR lock=0;
  583.   int i;
  584.  
  585.   for (i = 0 ; i < NUMBBNAMES ; i++)
  586.   { strcpy(buffer, device);
  587.     if (AddPart(buffer, BadBlockFileNames[i], DNAME_SIZE))
  588.     { if (lock = Lock(buffer, ACCESS_READ))
  589.       { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("\nFound existing %s file\n", BadBlockFileNames[i]);
  590.     break;
  591.       }
  592.     }
  593.   }
  594.  
  595.   return lock;
  596. }
  597.  
  598. /* Read existing bad blocks file into memory (struct BadBlockList) */
  599.  
  600. static struct BadBlockList *readbadblocks(BPTR bbflock)
  601. { ULONG bblkey = ((struct FileLock *)BADDR(bbflock))->fl_Key, badkey;
  602.   ULONG *header;
  603.   struct BadBlockList *bbl = NULL, *bbl1, *bblc;
  604.   int type=T_SHORT, error, numblocks, totblocks=0, blkinlist=0, i;
  605.  
  606.   do
  607.   { if (header = readblock(bblkey))
  608.     { if (error = checkblock(header, bblkey, type, ST_FILE))
  609.       { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("readbadblocks: error %ld\n", error);
  610.     FreeVec(header);
  611.     freebadblocklist(bbl);
  612.     return NULL;
  613.       }
  614.       if (numblocks = header[FILE_BLOCKCOUNT])
  615.       { for (i = 0 ; i < numblocks ; i++)
  616.     { if (!bbl) if (!(bblc = bbl = AllocMem(sizeof(struct BadBlockList), MEMF_CLEAR))) return NULL;
  617.       if ((badkey = header[mydiskdev.dd_BlockSizeL+FILE_DATABLOCK1-i]) < mydiskdev.dd_Reserved || badkey > mydiskdev.dd_HighKey)
  618.       { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("readbadblocks: invalid bad block number %lu\n", badkey);
  619.         continue;
  620.       }
  621.       if (blkinlist == BBL_SIZE)
  622.       { if (!(bbl1 = AllocMem(sizeof(struct BadBlockList), MEMF_CLEAR)))
  623.         { freebadblocklist(bbl);
  624.           FreeVec(header);
  625.           return NULL;
  626.         }
  627.         bblc->bbl_Link = bbl1;
  628.         bblc = bbl1;
  629.         blkinlist = 0;
  630.       }
  631.       bblc->bbl_BadBlocks[blkinlist++] = badkey;
  632.       totblocks++;
  633.     }
  634.       }
  635.       bblkey = header[mydiskdev.dd_BlockSizeL+FILE_EXTENSION];
  636.       type = T_LIST;
  637.       FreeVec(header);
  638.     }
  639.     else 
  640.     { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("readbadblocks: error %ld\n", DeviceIO->io_Error);
  641.       break;
  642.     }
  643.   } while (bblkey);
  644.  
  645.   if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("readbadblocks: total of %ld existing bad blocks\n", totblocks);
  646.   return bbl;
  647. }
  648.  
  649. /* Write bad block list in memory back into a bad blocks file on disk */
  650.  
  651. static int writebadblocks(struct BadBlockList *bbl, BPTR bbflock)
  652. { ULONG bblkey, extkey, chainkey;
  653.   ULONG *headerblock, *extblock=NULL, *fileblock;
  654.   UWORD blocksize = mydiskdev.dd_DOSType & 0x1 ? 4*mydiskdev.dd_BlockSizeL : 4*(mydiskdev.dd_BlockSizeL-DATA_DATABYTES);
  655.   int error, bblk, blkptr, totblocks=0;
  656.  
  657.   if (bbflock)
  658.   { bblkey = ((struct FileLock *)BADDR(bbflock))->fl_Key;
  659.     if (headerblock = readblock(bblkey))
  660.     { if (error = checkblock(headerblock, bblkey, T_SHORT, ST_FILE))
  661.       { Printf("writebadblocks: Invalid header block (error %ld)\n", error);
  662.     FreeVec(headerblock);
  663.     return error;
  664.       }
  665.       else clearblockptrs(headerblock);
  666.     }
  667.     else
  668.     { Printf("writebadblocks: Couldn't read header block (error %ld)\n", DeviceIO->io_Error);
  669.       return DeviceIO->io_Error;
  670.     }
  671.   }
  672.   else
  673.   { if (bblkey = getfreeblock(bitmap))
  674.     { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("writebadblocks: Allocated key %lu for file header\n", bblkey);
  675.       if (!(headerblock = initheader(bblkey, mydiskdev.dd_RootKey, T_SHORT, ST_FILE, BadBlockFileNames[0])))
  676.       { PutStr("writebadblocks: No memory for fileheader\n");
  677.     return ERROR_NO_FREE_STORE;
  678.       }
  679.       if (muBase = (struct muBase *)OpenLibrary(MULTIUSERNAME, 39))
  680.       { headerblock[mydiskdev.dd_BlockSizeL+FILE_OWNER] = muGetTaskOwner(NULL);
  681.     CloseLibrary((struct Library *)muBase);
  682.     muBase = NULL;
  683.       }
  684.     }
  685.     else
  686.     { PutStr("writebadblocks: Volume is full\n");
  687.       return ERROR_DISK_FULL;
  688.     }
  689.   }
  690.  
  691.   blkptr = mydiskdev.dd_BlockSizeL+FILE_DATABLOCK1;
  692.  
  693.   if (bbl)
  694.   { if (headerblock[FILE_FIRSTBLOCK] = bbl->bbl_BadBlocks[0])
  695.     { fileblock = headerblock;
  696.       do
  697.       { for (bblk = 0 ; bblk < BBL_SIZE ; bblk++)
  698.     { fileblock[blkptr--] = bbl->bbl_BadBlocks[bblk];
  699.       fileblock[FILE_BLOCKCOUNT]++;
  700.       totblocks++;
  701.  
  702.       if (bblk + 1 < BBL_SIZE)
  703.         if (bbl->bbl_BadBlocks[bblk+1] == 0) break;
  704.  
  705.       if (blkptr < FILE_DATABLOCKS)
  706.       { if (extkey = fileblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION])
  707.         { if (extblock = readblock(extkey))
  708.           { if (error = checkblock(extblock, extkey, T_LIST, ST_FILE))
  709.         { Printf("writebadblocks: Invalid extension block (error %ld)\n", error);
  710.           FreeVec(extblock);
  711.           FreeVec(headerblock);
  712.           return error;
  713.         }
  714.         else clearblockptrs(extblock);
  715.           }
  716.           else
  717.           { Printf("writebadblocks: Couldn't read extension block (error %ld)\n", DeviceIO->io_Error);
  718.         FreeVec(headerblock);
  719.         return DeviceIO->io_Error;
  720.           }
  721.         }
  722.         else if (extkey = getfreeblock(bitmap))
  723.         { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("writebadblocks: Allocated key %lu for extension block\n", extkey);
  724.           if (!(extblock = initheader(extkey, bblkey, T_LIST, ST_FILE, "")))
  725.           { PutStr("writebadblocks: No memory for file extension block\n");
  726.         FreeVec(headerblock);
  727.         return ERROR_NO_FREE_STORE;
  728.           }
  729.           fileblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION] = extkey;
  730.         }
  731.         else
  732.         { PutStr("writebadblocks: Volume is full\n");
  733.           if (extblock) FreeVec(extblock);
  734.           FreeVec(headerblock);
  735.           return ERROR_DISK_FULL;
  736.         }
  737.  
  738.         if (fileblock != headerblock)
  739.         { sumblock(fileblock);
  740.           if (error = writeblock(fileblock, fileblock[FEXT_OWNKEY]))
  741.           { Printf("writebadblocks: Couldn't write extension block (error %ld)\n", error);
  742.         FreeVec(extblock);
  743.         FreeVec(fileblock);
  744.         return error;
  745.           }
  746.           else FreeVec(fileblock);
  747.         }
  748.         fileblock = extblock;
  749.         extblock = NULL;
  750.         blkptr = mydiskdev.dd_BlockSizeL+FILE_DATABLOCK1;
  751.       }
  752.     }
  753.       } while (bbl = bbl->bbl_Link);
  754.  
  755. /* write back last extension block */
  756.  
  757.       if (fileblock != headerblock)
  758.       { fileblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION] = 0;
  759.     sumblock(fileblock);
  760.     if (error = writeblock(fileblock, fileblock[FEXT_OWNKEY]))
  761.     { Printf("writebadblocks: Couldn't write extension block (error %ld)\n", error);
  762.       FreeVec(fileblock);
  763.       return error;
  764.     }
  765.     else FreeVec(fileblock);
  766.       }
  767.       else headerblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION] = 0;
  768.     }
  769.     else headerblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION] = 0;
  770.   }
  771.   else headerblock[mydiskdev.dd_BlockSizeL+FILE_EXTENSION] = 0;
  772.  
  773. /* write back file header */
  774.  
  775.   headerblock[mydiskdev.dd_BlockSizeL+FILE_PROTECTION] = FIBF_HOLD | FIBF_ARCHIVE | FIBF_OTR_EXECUTE |
  776.     FIBF_GRP_EXECUTE | FIBF_READ | FIBF_WRITE | FIBF_DELETE;
  777.   headerblock[mydiskdev.dd_BlockSizeL+FILE_BYTESIZE] = totblocks * blocksize;
  778.   DateStamp((struct DateStamp *)&headerblock[mydiskdev.dd_BlockSizeL+FILE_DAYS]);
  779.  
  780.   if (!bbflock)
  781.   { if ((chainkey = gethashchain(rootblock, headerblock)) == (ULONG)(-1L))
  782.     { PutStr("writebadblocks: Couldn't get chain pointer\n");
  783.       FreeVec(headerblock);
  784.       return -1;
  785.     }
  786.     headerblock[mydiskdev.dd_BlockSizeL+FILE_HASHCHAIN] = chainkey;
  787.     sumblock(headerblock);
  788.     if (error = writeblock(headerblock, bblkey))
  789.     { Printf("writebadblocks: Couldn't write file header block (error %ld)\n", error);
  790.       FreeVec(headerblock);
  791.       return error;
  792.     }
  793.     if (error = hashlink(rootblock, headerblock))
  794.     { Printf("writebadblocks: Couldn't link file header to directory (error %ld)\n", error);
  795.       FreeVec(headerblock);
  796.       return error;
  797.     }
  798.   }
  799.   else
  800.   { sumblock(headerblock);
  801.     if (error = writeblock(headerblock, bblkey))
  802.     { Printf("writebadblocks: Couldn't write file header block (error %ld)\n", error);
  803.       FreeVec(headerblock);
  804.       return error;
  805.     }
  806.   }
  807.  
  808.   FreeVec(headerblock);
  809.   if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("writebadblocks: total of %ld bad blocks mapped out\n", totblocks);
  810.   return 0;
  811. }
  812.  
  813. static ULONG getfreeblock(ULONG *bitmap)
  814. { ULONG block=0, goodblock=0;
  815.  
  816.   do
  817.   { if (block = findfreeblock(bitmap, block))
  818.     { if (checkbadblock(block)) continue;
  819.       else
  820.       { allocblock(bitmap, block);
  821.     goodblock = block;
  822.     break;
  823.       }
  824.     }
  825.   } while (block);
  826.  
  827.   return goodblock;
  828. }
  829.  
  830. static void freebadblocklist(struct BadBlockList *bbl)
  831. { struct BadBlockList *bblc=bbl, *nextbbl;
  832.  
  833.   while (bblc)
  834.   { nextbbl = bblc->bbl_Link;
  835.     FreeMem(bblc, sizeof(struct BadBlockList));
  836.     bblc = nextbbl;
  837.   } 
  838. }
  839.  
  840. static BOOL checkbadblock(ULONG KeyID)
  841. { struct BadBlockList *bblc;
  842.   int i;
  843.  
  844.   for (bblc = BBList ; bblc ; bblc = bblc->bbl_Link)
  845.     for (i = 0 ; i < BBL_SIZE ; i++)
  846.     { if (bblc->bbl_BadBlocks[i] == KeyID) return TRUE;
  847.       if (bblc->bbl_BadBlocks[i] == 0) return FALSE;
  848.     }
  849.  
  850.   return FALSE;
  851. }
  852.  
  853. static void mapbadblock(ULONG badcyl, ULONG badhead, ULONG badsector)
  854. { ULONG lowsec = mydiskdev.dd_LowCyl * mydiskdev.dd_SectorsPerCyl;
  855.   ULONG badsec, badkey, lowbadsec, highbadsec, lowbadkey, highbadkey;
  856.  
  857.   badsec = badcyl*mydiskdev.dd_SectorsPerCyl + badhead*mydiskdev.dd_SectorsPerTrack + badsector;
  858.   badkey = (badsec - lowsec) / mydiskdev.dd_SectorsPerBlock;
  859.   if (checkbadblock(badkey)) Printf("old bad block found (sector %lu, key %lu)\n", badsec, badkey);
  860.   else
  861.   { Printf("new bad block found (sector %lu, key %lu)\n", badsec, badkey);
  862.     mydiskdev.dd_Flags |= DDFF_MODIFIED;
  863.     if (!strcmp(mydiskdev.dd_DeviceName, TD_NAME))
  864.     { lowbadsec = badcyl*mydiskdev.dd_SectorsPerCyl + badhead*mydiskdev.dd_SectorsPerTrack;
  865.       highbadsec = lowbadsec + mydiskdev.dd_SectorsPerTrack - 1;
  866.       lowbadkey = (lowbadsec - lowsec) / mydiskdev.dd_SectorsPerBlock;
  867.       highbadkey = (highbadsec - lowsec) / mydiskdev.dd_SectorsPerBlock;
  868.       if (lowbadkey < mydiskdev.dd_Reserved) lowbadkey = mydiskdev.dd_Reserved;
  869.       for (badkey = lowbadkey ; badkey <= highbadkey ; badkey++)
  870.       { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("adding bad key %lu\n", badkey);
  871.     if (!addbadblock(badkey)) PutStr("Warning: failed to add bad block\n\n");
  872.       }
  873.     }
  874.     else
  875.     { if (badkey >= mydiskdev.dd_Reserved)
  876.       { if (mydiskdev.dd_Flags & DDFF_VERBOSE) Printf("adding bad key %lu\n", badkey);
  877.     if (!addbadblock(badkey)) PutStr("Warning: failed to add bad block\n\n");
  878.       }
  879.     }
  880.   }
  881.   PutStr("\n");
  882. }
  883.  
  884. static BOOL addbadblock(ULONG KeyID)
  885. { struct BadBlockList *bblc;
  886.   int i;
  887.  
  888.   if (!BBList) if (!(BBList = AllocMem(sizeof(struct BadBlockList), MEMF_CLEAR))) return FALSE;
  889.  
  890.   for (bblc = BBList ; bblc ; bblc = bblc->bbl_Link)
  891.   { for (i = 0 ; i < BBL_SIZE ; i++)
  892.     { if (bblc->bbl_BadBlocks[i] == KeyID) return TRUE;
  893.       if (bblc->bbl_BadBlocks[i] == 0)
  894.       { if (allocblock(bitmap, KeyID))
  895.     { bblc->bbl_BadBlocks[i] = KeyID;
  896.       return TRUE;
  897.     }
  898.     else
  899.     { Printf("Key %lu already marked in use in bitmap\n", KeyID);
  900.       return FALSE;
  901.     }
  902.       }
  903.     }
  904.     if (!bblc->bbl_Link) if (!(bblc->bbl_Link = AllocMem(sizeof(struct BadBlockList), MEMF_CLEAR))) return FALSE;
  905.   }
  906.  
  907.   return FALSE;
  908. }
  909.  
  910. static void freebadblocks(struct BadBlockList *bbl)
  911. { struct BadBlockList *bblc=bbl;
  912.   ULONG key;
  913.   int i;
  914.  
  915.   while (bblc)
  916.   { for (i = 0 ; i < BBL_SIZE ; i++)
  917.     { if (key = bblc->bbl_BadBlocks[i]) freeblock(bitmap, key);
  918.       else break;
  919.     }
  920.     bblc = bblc->bbl_Link;
  921.   } 
  922. }
  923.  
  924. static __inline BOOL checkprotection(struct IOStdReq *ioreq)
  925. { ioreq->io_Command = TD_PROTSTATUS;
  926.   if (!DoIO((struct IORequest *)ioreq)) return (BOOL)ioreq->io_Actual;
  927.   else return TRUE;
  928. }
  929.  
  930. static __inline BOOL checkstate(struct IOStdReq *ioreq)
  931. { ioreq->io_Command = TD_CHANGESTATE;
  932.   if (!DoIO((struct IORequest *)ioreq)) return (BOOL)ioreq->io_Actual;
  933.   else return TRUE;
  934. }
  935.